#pragma once

using namespace System;
using namespace NUnit::Framework;
using namespace LatoolNet;

namespace LatoolNetTest {

	[TestFixture]
	public ref class ComplexGeneralMatrixTest {
	public:
		[Test]
		void TestSetGetValue() {

			int rownum = 6;
			int colnum = 6;

			array<Complex, 2>^ expected = gcnew array<Complex, 2>(rownum, colnum);

			ComplexMatrix ^ actual = gcnew ComplexMatrix(rownum, colnum);

			Assert::AreEqual(MatrixType::ComplexGeneral, actual->Type, "Test: Type");

			Random ^ randomgen = gcnew Random();
			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					double real = randomgen->NextDouble() * 10 - 5;
					double imag = randomgen->NextDouble() * 10 - 5;

					expected[i, j] = Complex(real, imag); 
					actual[i, j] = Complex(real, imag);
				}
			}

			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					Assert::AreEqual(expected[i, j].Real, actual[i, j].Real, 1e-10, "Test: Set/Get value");
					Assert::AreEqual(expected[i, j].Imag, actual[i, j].Imag, 1e-10, "Test: Set/Get value");

				}
			}

		};

		[Test]
		void TestInvertMatrix() {
			
			int rownum = 8;
			int colnum = 8;

			ComplexMatrix ^ a = gcnew ComplexMatrix(rownum, colnum);
			
			Random ^ randomgen = gcnew Random();
			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					double real = randomgen->NextDouble() * 10 - 5;
					double imag = randomgen->NextDouble() * 10 - 5;
					a[i, j] = Complex(real, imag);
				}
			}

			ComplexMatrix ^ ainv = a->Clone()->Inv();

			ComplexMatrix ^ ainvinv = ainv->Clone()->Inv();

			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					Assert::AreEqual(a[i, j].Real, ainvinv[i, j].Real, 1e-10, "Test: inv");
					Assert::AreEqual(a[i, j].Imag, ainvinv[i, j].Imag, 1e-10, "Test: inv");												
				}
			}


		};


		[Test]
		void TestFactorizedSolve() {
			
			int rownum = 8;
			int colnum = 8;

			ComplexMatrix ^a = gcnew ComplexMatrix(rownum, colnum);
			Random ^ randomgen = gcnew Random();
			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					double real = randomgen->NextDouble() * 10 - 5;
					double imag = randomgen->NextDouble() * 10 - 5;
					a[i, j] = Complex(real, imag);
				}
			}

			ComplexMatrix ^expected = gcnew ComplexMatrix(rownum, 1);

			for (int i = 0; i < rownum; i++) {
				double real = randomgen->NextDouble() * 10 - 5;				
				double imag = randomgen->NextDouble() * 10 - 5;				
				expected[i, 0] = Complex(real, imag);
			}

			ComplexMatrix ^ b = a * expected;

			//LUFactorization::Factorize(a);
			LinearEquation::Factorize(a);

			//LUFactorization::Solve(a, b);
			LinearEquation::Solve(a, b);

			for (int i = 0; i < rownum; i++) {
				Assert::AreEqual(expected[i, 0].Real, b[i, 0].Real, 1e-10, "Test: Factorized Solve.");
				Assert::AreEqual(expected[i, 0].Imag, b[i, 0].Imag, 1e-10, "Test: Factorized Solve.");

			}


		};

		[Test]
		void TestRepeatedFactorizedSolve() {
			
			int rownum = 8;
			int colnum = 8;

			ComplexMatrix ^a = gcnew ComplexMatrix(rownum, colnum);
			Random ^ randomgen = gcnew Random();
			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					double real = randomgen->NextDouble() * 10 - 5;
					double imag = randomgen->NextDouble() * 10 - 5;
					a[i, j] = Complex(real, imag);
				}
			}

			ComplexMatrix ^expected = gcnew ComplexMatrix(rownum, 1);

			for (int i = 0; i < rownum; i++) {
				double real = randomgen->NextDouble() * 10 - 5;				
				double imag = randomgen->NextDouble() * 10 - 5;				
				expected[i, 0] = Complex(real, imag);
			}

			ComplexMatrix ^ b = a * expected;

			ComplexMatrix ^expected2 = gcnew ComplexMatrix(rownum, 1);

			for (int i = 0; i < rownum; i++) {
				double real = randomgen->NextDouble() * 10 - 5;				
				double imag = randomgen->NextDouble() * 10 - 5;				
				expected2[i, 0] = Complex(real, imag);
			}

			ComplexMatrix ^ b2 = a * expected2;

			//LUFactorization::Factorize(a);
			LinearEquation::Factorize(a);

			//LUFactorization::Solve(a, b);
			LinearEquation::Solve(a, b);

			//LUFactorization::Solve(a, b2);
			LinearEquation::Solve(a, b2);

			for (int i = 0; i < rownum; i++) {
				Assert::AreEqual(expected[i, 0].Real, b[i, 0].Real, 1e-10, "Test: Repeated Factorized Solve.");
				Assert::AreEqual(expected[i, 0].Imag, b[i, 0].Imag, 1e-10, "Test: Repeated Factorized Solve.");

			}

			for (int i = 0; i < rownum; i++) {
				Assert::AreEqual(expected2[i, 0].Real, b2[i, 0].Real, 1e-10, "Test: Repeated Factorized Solve.");
				Assert::AreEqual(expected2[i, 0].Imag, b2[i, 0].Imag, 1e-10, "Test: Repeated Factorized Solve.");

			}

		};

		[Test]
		void TestRepeatedSolve() {
			
			int rownum = 8;
			int colnum = 8;

			ComplexMatrix ^a = gcnew ComplexMatrix(rownum, colnum);
			Random ^ randomgen = gcnew Random();
			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					double real = randomgen->NextDouble() * 10 - 5;
					double imag = randomgen->NextDouble() * 10 - 5;
					a[i, j] = Complex(real, imag);
				}
			}

			ComplexMatrix ^expected = gcnew ComplexMatrix(rownum, 1);

			for (int i = 0; i < rownum; i++) {
				double real = randomgen->NextDouble() * 10 - 5;				
				double imag = randomgen->NextDouble() * 10 - 5;				
				expected[i, 0] = Complex(real, imag);
			}

			ComplexMatrix ^ b = a * expected;

			ComplexMatrix ^expected2 = gcnew ComplexMatrix(rownum, 1);

			for (int i = 0; i < rownum; i++) {
				double real = randomgen->NextDouble() * 10 - 5;				
				double imag = randomgen->NextDouble() * 10 - 5;				
				expected2[i, 0] = Complex(real, imag);
			}

			ComplexMatrix ^ b2 = a * expected2;

			//LUFactorization::Solve(a, b);
			LinearEquation::Solve(a, b);

			//LUFactorization::Solve(a, b2);
			LinearEquation::Solve(a, b2);

			for (int i = 0; i < rownum; i++) {
				Assert::AreEqual(expected[i, 0].Real, b[i, 0].Real, 1e-10, "Test: Repeated Factorized Solve.");
				Assert::AreEqual(expected[i, 0].Imag, b[i, 0].Imag, 1e-10, "Test: Repeated Factorized Solve.");

			}

			for (int i = 0; i < rownum; i++) {
				Assert::AreEqual(expected2[i, 0].Real, b2[i, 0].Real, 1e-10, "Test: Repeated Factorized Solve.");
				Assert::AreEqual(expected2[i, 0].Imag, b2[i, 0].Imag, 1e-10, "Test: Repeated Factorized Solve.");

			}

		};

		[Test]
		void TestSolve() {
			
			int rownum = 6;
			int colnum = 6;

			ComplexMatrix ^a = gcnew ComplexMatrix(rownum, colnum);
			Random ^ randomgen = gcnew Random();
			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					double real = randomgen->NextDouble() * 10 - 5;
					double imag = randomgen->NextDouble() * 10 - 5;
					a[i, j] = Complex(real, imag);
				}
			}

			ComplexMatrix ^expected = gcnew ComplexMatrix(rownum, 1);

			for (int i = 0; i < rownum; i++) {
				double real = randomgen->NextDouble() * 10 - 5;
				double imag = randomgen->NextDouble() * 10 - 5;	
				expected[i, 0] = Complex(real, imag);	
			}

			ComplexMatrix ^ b = a * expected;

			//LUFactorization::Solve(a, b);
			LinearEquation::Solve(a, b);

			for (int i = 0; i < rownum; i++) {
				Assert::AreEqual(expected[i, 0].Real, b[i, 0].Real, 1e-10, "Test: Factorized Solve.");
				Assert::AreEqual(expected[i, 0].Imag, b[i, 0].Imag, 1e-10, "Test: Factorized Solve.");

			}


		};


	};
}
